<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>数独</title>
    <style>
        html{
            width: 100%;
            height: 100%;
        }
        body{
            width: 100%;
            height: 100%;
            margin: 0;
            display: flex;
            justify-content: center;
            position: relative;
        }
        .overtrue{
            width: 100%;
            height: 100%;
            display: flex;
            justify-content: center;
            background-color: darkolivegreen;
            position: relative;
        }
        .body-box{
            width: 100%;
            aspect-ratio: 1;
            position: relative;
            background-color: saddlebrown;
            border-radius: 4px;
        }

        .lattice-box{
            background-color: saddlebrown;
            width: 90%;
            height: 90%;

            display: flex;
            flex-wrap: wrap;
            border: 3px solid black;
            justify-content: space-between;

            border-radius: 4px;

            position: absolute;
            top:50%;
            left: 50%;
            transform: translate(-50%,-50%);
        }
        .lattice{
            width: 10.7%;
            height: 10.7%;
            background-color: #fcd2a5;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 100%;
        }
        .lattice1{
            background-color: bisque;
        }
        .lattice1:hover{
            width: 10%;
            height: 10%;
            margin: 0.35%;
            cursor: pointer;
        }
        .lattice1-active{
            background-color: #ffffff;
        }
        .mask{
            width: 100%;
            height: 100%;
            z-index: 0;
            transition: all 0.2s ease;
            position: absolute;
        }
        .mask-active{
            z-index: 1;
        }
        .fall-box{
            position: absolute;
            width: 100%;
            height: 6%;
            transition:background  0.2s ease;
            opacity: 0;
            z-index: 0;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .fall-box-active{
            z-index: 1;
            opacity: 1;
        }
        .fall-item{
            display: flex;
            justify-content: center;
            align-items: center;
            background-color: bisque;
            border:2px solid saddlebrown;
            border-radius: 4px;
            cursor: pointer;
        }
        .fall-item:hover{
            opacity: 0.9;
            border-radius: 50%;
        }
        .red{
            background-color:darkred;
            color: #faebdd;
        }
        .over{
            position: absolute;
            width: 100%;
            height: 90%;
            opacity: 0;
            background-color: rgba(0,0,0,0.4);
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            z-index: 0;
        }
        .over *{
            color: bisque;
        }
        .over-active{
            z-index: 1;
            color: bisque;
            opacity: 1;
            background-color: rgba(0,0,0,0.4);
        }
        .grade-box{
            display: flex;
            width: 100%;
            justify-content: center;
            align-items: center;
        }
        #reGame{
            width: 100%;
            height: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
            flex-direction: column;
        }
        .button{
            width: 10%;
            margin: 5%;
            aspect-ratio: 1;
            background-color: rgba(0,0,0,0);
            border: none;
            font-size: 32px;
            cursor: pointer;
        }
        .reGame{
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div class="mask"></div>
    <div class="over">
        <div id="gameOver">
            <h1>完 成</h1>
            <h2 id="grade">级别 </h2>
            <h2 id="time">用时 </h2>
        </div>
        <div id="reGame">
            <h2 class="reGame">重玩</h2>
            <div class="grade-box">
                <button class="button" id="addTime">+</button>
                <h2 id="grade1">级别 </h2>
                <button class="button" id="unaddTime">-</button>
            </div>
        </div>
    </div>
    <div class="overtrue">
        <div class="body-box">
            <div class="lattice-box"></div>
        </div>
        <div class="fall-box">
            <div class="fall-item">1</div>
            <div class="fall-item">2</div>
            <div class="fall-item">3</div>
            <div class="fall-item">4</div>
            <div class="fall-item">5</div>
            <div class="fall-item">6</div>
            <div class="fall-item">7</div>
            <div class="fall-item">8</div>
            <div class="fall-item">9</div>
        </div>
    </div>
<script>
    ////数据区
    let digit=[];//81位数字
    let grade=4;//等级n,打乱n次，每个格子去掉[n,n+1]个数字
    let clickElement=null;
    let numberElement=[];
    let clickXY={x:null,y:null};
    let sizeType=0;//屏幕是横还是竖 1-横 2-竖
    let unokNumber=0;
    let okNumber=0;
    let timeValue=0;
    let game=0;



    ////函数区
    //入口 页面载入后运行
    window.onload=function(){
        console.log("overtrue")

        //屏幕适配
        Adapter();

        //初始化
        Initialization();

        //固盘生成
        Generate();

        //固盘打乱
        Disruption(grade);

        //摘除数字生成终盘
        End(grade);

        //渲染
        Show();
    }

    //渲染
    function Show(){
        //获取overtrue元素
        const overtrueElement=document.querySelector('.lattice-box');

        //循环导入div
        for(let i=0;i<9;i++){
            for(let j=0;j<9;j++){
                //创建div
                const div=document.createElement('div');
                //存储
                numberElement[i][j]=div;
                //添加类名
                div.className='lattice'
                //如果该位置有数字则设计数字
                if(digit[i][j]!==0){
                    div.textContent=`${digit[i][j]}`;
                }else{
                    //若没有数字则添加可操作类名
                    div.classList.add('lattice1')
                    //添加操作函数
                    div.addEventListener('click',function(){
                        //存储点击的元素
                        clickElement=div;
                        clickXY.x=i;
                        clickXY.y=j;
                        //给被点击的样式添加点击样式
                        div.classList.add('lattice1-active');
                        //换起遮罩层
                        document.querySelector('.mask').classList.add('mask-active');
                        //唤起数字选择区
                        if(sizeType===1){
                            if(j>=4) {
                                document.querySelector('.fall-box').style.left = `${window.innerWidth / 2 + window.innerHeight / 2}px`;
                            }else{
                                document.querySelector('.fall-box').style.left = `${window.innerWidth / 2 - window.innerHeight / 2 - window.innerWidth*0.13}px`
                            }
                        }else{
                            if(i<=4) {
                                document.querySelector('.fall-box').style.top =`${window.innerHeight/2-window.innerWidth/2-window.innerWidth*0.13}px`;
                            }else{
                                document.querySelector('.fall-box').style.top=`${window.innerWidth/2+window.innerHeight/2}px`;
                            }
                        }
                        FallBoxNo();
                    })
                }

                //画宫分隔线
                if(j===2||j===5){
                    div.style.borderRight='1.5px solid black'
                }
                if(i===2||i===5){
                    div.style.borderBottom='2px solid black'
                }
                //挂载
                overtrueElement.appendChild(div);
            }
        }
    }
    function reshow(){
        for(let i=0;i<9;i++){
            for(let j=0;j<9;j++){
                numberElement[i][j].classList.remove('lattice1')
                if(digit[i][j]!=0){
                    numberElement[i][j].innerText=`${digit[i][j]}`;
                }else{
                    numberElement[i][j].innerText='';
                    numberElement[i][j].classList.add('lattice1')
                    numberElement[i][j].addEventListener('click',function(){
                        //存储点击的元素
                        clickElement=numberElement[i][j];
                        clickXY.x=i;
                        clickXY.y=j;
                        //给被点击的样式添加点击样式
                        numberElement[i][j].classList.add('lattice1-active');
                        //换起遮罩层
                        document.querySelector('.mask').classList.add('mask-active');
                        //唤起数字选择区
                        if(sizeType===1){
                            if(j>=4) {
                                document.querySelector('.fall-box').style.left = `${window.innerWidth / 2 + window.innerHeight / 2}px`;
                            }else{
                                document.querySelector('.fall-box').style.left = `${window.innerWidth / 2 - window.innerHeight / 2 - window.innerWidth*0.13}px`
                            }
                        }else{
                            if(i<=4) {
                                document.querySelector('.fall-box').style.top =`${window.innerHeight/2-window.innerWidth/2-window.innerWidth*0.13}px`;
                            }else{
                                document.querySelector('.fall-box').style.top=`${window.innerWidth/2+window.innerHeight/2}px`;
                            }
                        }
                        FallBoxNo();
                    })
                }

            }
        }
    }

    //显示数字可填栏
    function FallBoxNo(num){
        document.querySelector('.fall-box').classList.add('fall-box-active');
    }

    //生成终盘
    function End(level){
        let n=0;
        let numberX=[];
        let numberY=[];
        let a=null;
        let b=null;

        for(let i=0;i<3;i++){
            for(let j=0;j<3;j++){
                n=Math.floor(Math.random()*(level+1)+level);
                for(let k=0;k<n;k++){
                    numberX=[i*3,i*3+1,i*3+2];
                    numberY=[j*3,j*3+1,j*3+2];

                    a=numberX[Math.floor(Math.random()*numberX.length)];
                    b=numberY[Math.floor(Math.random()*numberY.length)];
                    digit[a][b]=0;
                }
            }
        }
        for(let i=0;i<9;i++){
            for(let j=0;j<9;j++){
                if(digit[i][j]===0){
                    unokNumber++;
                }
            }
        }
    }

    //固盘打乱
    function Disruption(level){
        let n=0;//打乱当前进行的次数
        let number=[];
        let a=0;
        let b=0;
        let temp=0;

        //开始运行打乱
        while (n!==level){
            n++;
            a=Math.floor(Math.random()*9);
            number=[Math.floor(a/3)*3,Math.floor(a/3)*3+1,Math.floor(a/3)*3+2];
            number=number.filter(value=>value!==a);
            b=number[Math.floor(Math.random()*2)];
            for(let i=0;i<9;i++){
                temp=digit[a][i];
                digit[a][i]=digit[b][i];
                digit[b][i]=temp;
            }

            a=Math.floor(Math.random()*9);
            number=[Math.floor(a/3)*3,Math.floor(a/3)*3+1,Math.floor(a/3)*3+2];
            number=number.filter(value=>value!==a);
            b=number[Math.floor(Math.random()*2)];
            for(let i=0;i<9;i++){
                temp=digit[i][a];
                digit[i][a]=digit[i][b];
                digit[i][b]=temp;
            }

        }
    }

    //屏幕适配-计算宽高比例，主要显示区为一个正方形，若比例>1则用显示区域的高为边长，否则用宽
    function Adapter(){
        let proportion=window.innerWidth/window.innerHeight;
        if(proportion>1){
            sizeType=1;
            document.querySelector('.body-box').style.width=`${window.innerHeight}px`;
            document.querySelector('.body-box').style.height=`${window.innerHeight}px`;
            document.querySelector('.fall-box').style.height=`${window.innerHeight}px`;
            document.querySelector('.fall-box').style.width=`${window.innerWidth*0.13}px`;
            document.querySelector('.fall-box').style.left=`${window.innerWidth/2+window.innerHeight/2}px`;
            document.querySelector('.fall-box').style.flexDirection="column";
            document.querySelectorAll('.fall-item').forEach(item=>{
                item.style.height=`${window.innerHeight*0.1}px`;
                item.style.width=`${window.innerHeight*0.1}px`;
            })
        }else{
            sizeType=2;
            document.querySelector('.body-box').style.width=`${window.innerWidth}px`;
            document.querySelector('.body-box').style.height=`${window.innerWidth}px`;
            document.querySelector('.overtrue').style.flexDirection="column";
            document.querySelector('.fall-box').style.height=`${window.innerWidth*0.13}px`;
            document.querySelector('.fall-box').style.width=`${window.innerWidth}px`;
            document.querySelector('.fall-box').style.top=`${window.innerWidth/2+window.innerHeight/2}px`;
            document.querySelector('.fall-box').style.display='flex';
            document.querySelectorAll('.fall-item').forEach(item=>{
                item.style.height=`${window.innerWidth*0.1}px`;
                item.style.width=`${window.innerWidth*0.1}px`;
            })
        }
    }

    //初始化
    function Initialization(){
        for(let i=0;i<9;i++){
            digit.push([0,0,0,0,0,0,0,0,0]);
            numberElement.push([0,0,0,0,0,0,0,0,0]);
        }
    }

    //固定盘生成-
    function Generate(){
        for(let i=0;i<9;i++){
            for(let j=0;j<9;j++){
                digit[i][j]=0;
            }
        }
        //按顺序(从左到右，从上到下)填数字
        let number=1;
        let btn=1;
        for(let i=0;i<9;i++){
            for(let j=0;j<9;j++){
                //检查所在行、列及小九宫格是否存在相同数字
                btn=1;
                while(btn){
                    if(Inspect(number,i,j)){
                        digit[i][j]=number;
                        number++;
                        btn=0;
                    }else{
                        number++;
                    }
                    if(number===10){
                        number=1;
                    }
                }
            }
        }
    }

    //检查器
    function Inspect(number,i,j){
        let latticeX=Math.floor(i/3);
        let latticeY=Math.floor(j/3);
        //行检查
        for(let ii=0;ii<9;ii++){
            if(number==digit[i][ii]){
                return false;
            }
        }
        //列检查
        for(let ii=0;ii<9;ii++){
            if(number==digit[ii][j]){
                return false;
            }
        }
        //宫检查
        for(let ii=latticeX*3;ii<(latticeX+1)*3;ii++){
            for(let jj=latticeY*3;jj<(latticeY+1)*3;jj++){
                if(number==digit[ii][jj]){
                    return false;
                }
            }
        }
        return true;
    }
    document.querySelectorAll('.fall-item').forEach(item=>{
        item.addEventListener('click',function (){
            clickElement.innerText=item.innerText;
            clickElement.classList.remove('lattice1-active');
            document.querySelector('.fall-box').classList.remove('fall-box-active');

            okNumber++;
            if(okNumber===1){
                let time=setInterval(function(){
                    timeValue++;
                    if(game===1){
                        clearInterval(time);
                    }
                },1000);
            }
            if(Inspect(item.innerText,clickXY.x,clickXY.y)){
                document.querySelector('.mask').classList.remove('mask-active');
                if(okNumber===unokNumber){
                    console.log('游戏结束')
                    game=1;
                    document.querySelector('.over').classList.add('over-active');
                    document.querySelector('#gameOver').style.display='flex';
                    document.querySelector('#grade').innerText+=` ${grade}`;
                    document.querySelector('#time').innerText+=` ${timeValue} s`;
                }
            }else{
                clickElement.classList.add('red')
                setTimeout(function (){
                    clickElement.classList.remove('red');
                    document.querySelector('.mask').classList.remove('mask-active');
                    clickElement.innerText='';
                },500)
                okNumber--;
            }
        })
    })
    document.querySelector('.mask').addEventListener('click',function (){
        document.querySelector('.mask').classList.remove('mask-active');
        clickElement.classList.remove('lattice1-active');
        document.querySelector('.fall-box').classList.remove('fall-box-active');
    })
    document.querySelector('#reGame').style.display='none';
    document.querySelector('.over').addEventListener('click',function(){
        document.querySelector('#gameOver').style.display='none';
        document.querySelector('#reGame').style.display='flex';
    })
    document.querySelector('#grade1').innerText+=`${grade}`;
    document.querySelector('#addTime').addEventListener('click',function(){
        if(grade<8){
            grade++;
        }
        document.querySelector('#grade1').innerText+=`${grade}`;
    })
    document.querySelector('#unaddTime').addEventListener('click',function(){
        if(grade>1){
            grade--;
        }
        document.querySelector('#grade1').innerText+=`${grade}`;
    })
    document.querySelector('.reGame').addEventListener('click',function(){
        document.querySelector('.over').classList.remove('over-active');
        document.querySelector('#reGame').style.display='none';
        document.querySelector('#gameOver').style.display='flex';
        Generate();
        let n=0;
        let reGame=setInterval(function(){
            Disruption(grade);
            reshow();
            n++;
            if(n===5){
                clearInterval(reGame);
            }
        },200)
        End(grade);
        reshow();
    })
</script>
</body>
</html>

